class Vue {
  constructor(options) {
    this.$data = options.data;
    this.$el =
      typeof options.el === "string"
        ? document.querySelector(options.el)
        : options.el;
    Observer(this.$data);
    Complie(this);
  }
}

// 数据劫持
function Observer(data) {
  if (!data || typeof data !== "object") return;
  // 获取对象键值对
  Object.entries(data).forEach(([key, value]) => {
    const deps = new Dep();
    Observer(value);
    // 数据劫持
    Object.defineProperty(data, key, {
      get() {
        console.log(`属性${key}被访问了， 值是${value}`);
        if (Dep.temp) {
          // 依赖收集
          deps.addSub(Dep.temp);
        }
        return value;
      },
      set(newValue) {
        console.log(`属性${key}从旧值${data[key]} => 新值是${newValue}`);
        value = newValue;
        Observer(newValue);
        // 通知更新
        deps.notify();
      },
    });
  });
}

// 模板编译
function Complie(vm) {
  // 文档碎片
  const fragment = document.createDocumentFragment();
  let child;
  // 1. 将 $el 上所有的节点 缓存 到 fragment
  while ((child = vm.$el.firstChild)) {
    fragment.append(child);
  }
  // 2. fragment 内容做替换 $data
  function complie_data(fragment) {
    // 循环所有的节点
    fragment.childNodes.forEach((node) => {
      // 元素节点
      if (node.nodeType === 1 && node.nodeName === "INPUT") {
        const attrs = Array.from(node.attributes);
        attrs.forEach((attr) => {
          if (attr.nodeName === "v-model") {
            const key = attr.nodeValue;
            const value = key.split('.').reduce(
              (total, current) => total[current],
              vm.$data  
            )
            node.value = value

            new Watch(vm, key, newValue => {
              node.value = newValue;
            })

            node.addEventListener('input', e => {
              const value = e.target.value;
              const keys = key.split('.');
              const result = keys.slice(0, keys.length - 1).reduce(
                (total, current) => total[current],
                vm.$data  
              )
              result[keys[keys.length - 1]] = value
            })
          }
        });
      }
      // 文本节点
      if (node.nodeType === 3) {
        // 保存文本内容
        const nodeValue = node.nodeValue;
        // 正则替换规则
        const pattern = /\{\{\s*(\S+)\s*\}\}/;
        // 正则检测本文内容
        const result = pattern.exec(nodeValue);
        if (result) {
          // 获取正则匹配的分组内容
          const key = result[1];
          // 获取对应的数据
          const keys = key.split(".");
          // 逐层解析数据
          const value = keys.reduce(
            (total, current) => total[current],
            vm.$data
          );
          // 正则  将原本内容替换
          node.nodeValue = nodeValue.replace(pattern, value);

          new Watch(vm, key, (newValue) => {
            node.nodeValue = nodeValue.replace(pattern, newValue);
          });
        }
      }

      complie_data(node);
    });
  }
  complie_data(fragment);

  // 3. fragment 放回 $el
  vm.$el.append(fragment);
}

// 发布-订阅
class Dep {
  constructor() {
    this.subscribers = [];
  }
  addSub(sub) {
    this.subscribers.push(sub);
  }
  notify() {
    this.subscribers.forEach((v) => v.update());
  }
}

class Watch {
  constructor(vm, key, callback) {
    this.vm = vm;
    this.key = key;
    this.callback = callback;

    Dep.temp = this;
    // 触发 get
    key.split(".").reduce((total, current) => total[current], vm.$data);
    Dep.temp = null;
  }
  update() {
    const value = this.key
      .split(".")
      .reduce((total, current) => total[current], this.vm.$data);
    this.callback(value);
  }
}
